home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / PRODUCT.PY < prev    next >
Encoding:
Python Source  |  2000-08-14  |  16.2 KB  |  477 lines

  1. ##############################################################################
  2. # Zope Public License (ZPL) Version 1.0
  3. # -------------------------------------
  4. # Copyright (c) Digital Creations.  All rights reserved.
  5. # This license has been certified as Open Source(tm).
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. # 1. Redistributions in source code must retain the above copyright
  10. #    notice, this list of conditions, and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. #    notice, this list of conditions, and the following disclaimer in
  13. #    the documentation and/or other materials provided with the
  14. #    distribution.
  15. # 3. Digital Creations requests that attribution be given to Zope
  16. #    in any manner possible. Zope includes a "Powered by Zope"
  17. #    button that is installed by default. While it is not a license
  18. #    violation to remove this button, it is requested that the
  19. #    attribution remain. A significant investment has been put
  20. #    into Zope, and this effort will continue if the Zope community
  21. #    continues to grow. This is one way to assure that growth.
  22. # 4. All advertising materials and documentation mentioning
  23. #    features derived from or use of this software must display
  24. #    the following acknowledgement:
  25. #      "This product includes software developed by Digital Creations
  26. #      for use in the Z Object Publishing Environment
  27. #      (http://www.zope.org/)."
  28. #    In the event that the product being advertised includes an
  29. #    intact Zope distribution (with copyright and license included)
  30. #    then this clause is waived.
  31. # 5. Names associated with Zope or Digital Creations must not be used to
  32. #    endorse or promote products derived from this software without
  33. #    prior written permission from Digital Creations.
  34. # 6. Modified redistributions of any form whatsoever must retain
  35. #    the following acknowledgment:
  36. #      "This product includes software developed by Digital Creations
  37. #      for use in the Z Object Publishing Environment
  38. #      (http://www.zope.org/)."
  39. #    Intact (re-)distributions of any official Zope release do not
  40. #    require an external acknowledgement.
  41. # 7. Modifications are encouraged but must be packaged separately as
  42. #    patches to official Zope releases.  Distributions that do not
  43. #    clearly separate the patches from the original work must be clearly
  44. #    labeled as unofficial distributions.  Modifications which do not
  45. #    carry the name Zope may be packaged in any form, as long as they
  46. #    conform to all of the clauses above.
  47. # Disclaimer
  48. #   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
  49. #   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50. #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  51. #   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
  52. #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  53. #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  54. #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  55. #   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  56. #   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  57. #   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  58. #   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  59. #   SUCH DAMAGE.
  60. # This software consists of contributions made by Digital Creations and
  61. # many individuals on behalf of Digital Creations.  Specific
  62. # attributions are listed in the accompanying credits file.
  63. ##############################################################################
  64. """Product objects
  65. """
  66. # The new Product model:
  67. #   Products may be defined in the Products folder or by placing directories
  68. #   in lib/python/Products.
  69. #   Products in lib/python/Products may have up to three sources of information:
  70. #       - Static information defined via Python.  This information is
  71. #         described and made available via __init__.py.
  72. #       - Dynamic object data that gets copied into the Bobobase.
  73. #         This is contained in product.dat (which is obfuscated).
  74. #       - Static extensions supporting the dynamic data.  These too
  75. #         are obfuscated.
  76. #   Products may be copied and pasted only within the products folder.
  77. #   If a product is deleted (or cut), it is automatically recreated
  78. #   on restart if there is still a product directory.
  79.  
  80.  
  81. import Globals, OFS.Folder, OFS.SimpleItem, os, string, Acquisition, Products
  82. import regex, zlib, Globals, cPickle, marshal, rotor
  83. import ZClasses, ZClasses.ZClass, AccessControl.Owned
  84.  
  85. from OFS.Folder import Folder
  86. from string import rfind, atoi, find, strip, join
  87. from Factory import Factory
  88. from Permission import PermissionManager
  89. import ZClasses, ZClasses.ZClass
  90. from HelpSys.HelpSys import ProductHelp
  91.  
  92.  
  93. class ProductFolder(Folder):
  94.     "Manage a collection of Products"
  95.  
  96.     id        ='Products'
  97.     name=title='Product Management'
  98.     meta_type ='Product Management'
  99.     icon='p_/ProductFolder_icon'
  100.  
  101.     all_meta_types={'name': 'Product', 'action': 'manage_addProductForm'},
  102.     meta_types=all_meta_types
  103.  
  104.     # This prevents subobjects from being owned!
  105.     _owner=AccessControl.Owned.UnownableOwner
  106.  
  107.     def _product(self, name): return getattr(self, name)
  108.  
  109.     manage_addProductForm=Globals.HTMLFile('addProduct',globals())
  110.     def manage_addProduct(self, id, title, REQUEST=None):
  111.         ' '
  112.         i=Product(id, title)
  113.         self._setObject(id,i)
  114.         if REQUEST is not None:
  115.             return self.manage_main(self,REQUEST,update_menu=1)
  116.  
  117.     def _canCopy(self, op=0):
  118.         return 0
  119.  
  120. class Product(Folder, PermissionManager):
  121.     """Model a product that can be created through the web.
  122.     """
  123.     meta_type='Product'
  124.     icon='p_/Product_icon'
  125.     version=''
  126.     configurable_objects_=()
  127.     redistributable=0
  128.     import_error_=None
  129.     _isBeingUsedAsAMethod_=1
  130.  
  131.     def new_version(self,
  132.                     _intending=regex.compile("[.]?[0-9]+$").search, #TS
  133.                     ):
  134.         # Return a new version number based on the existing version.
  135.         v=str(self.version)
  136.         if not v: return '1.0'
  137.         if _intending(v) < 0: return v
  138.         l=rfind(v,'.')
  139.         return v[:l+1]+str(1+atoi(v[l+1:]))            
  140.                     
  141.     
  142.     meta_types=(
  143.         ZClasses.meta_types+PermissionManager.meta_types+
  144.         (
  145.             {
  146.                 'name': Factory.meta_type,
  147.                 'action': 'manage_addPrincipiaFactoryForm'
  148.                 },
  149.             )
  150.         )
  151.     
  152.     manage_addZClassForm=ZClasses.methods['manage_addZClassForm']
  153.     manage_addZClass    =ZClasses.methods['manage_addZClass']
  154.     manage_subclassableClassNames=ZClasses.methods[
  155.         'manage_subclassableClassNames']
  156.  
  157.     manage_options=(
  158.         Folder.manage_options+
  159.         (
  160.         {'label':'Distribution', 'action':'manage_distributionView',
  161.          'help':('OFSP','Product_Distribution.stx')},
  162.         )
  163.         )
  164.  
  165.     manage_distributionView=Globals.HTMLFile('distributionView',globals())
  166.  
  167.     _properties=Folder._properties+(
  168.         {'id':'version', 'type': 'string'},
  169.         )
  170.  
  171.     _reserved_names=('Help',)
  172.  
  173.     manage_addPrincipiaFactoryForm=Globals.HTMLFile('addFactory',globals())
  174.     def manage_addPrincipiaFactory(
  175.         self, id, title, object_type, initial, permission=None, REQUEST=None):
  176.         ' '
  177.         i=Factory(id, title, object_type, initial, permission)
  178.         self._setObject(id,i)
  179.         factory = self._getOb(id)
  180.         factory.initializePermission()
  181.         if REQUEST is not None:
  182.             return self.manage_main(self,REQUEST,update_menu=1)
  183.  
  184.     def __init__(self, id, title):
  185.         self.id=id
  186.         self.title=title
  187.         self._setObject('Help', ProductHelp('Help', id))
  188.         
  189.     def Destination(self):
  190.         "Return the destination for factory output"
  191.         return self
  192.     Destination__roles__=None
  193.  
  194.     def DestinationURL(self):
  195.         "Return the URL for the destination for factory output"
  196.         return self.REQUEST['BASE4']
  197.     DestinationURL__roles__=None
  198.  
  199.     def manage_distribute(self, version, RESPONSE, configurable_objects=[],
  200.                           redistributable=0):
  201.         "Set the product up to create a distribution and give a link"
  202.         if self.__dict__.has_key('manage_options'):
  203.             raise TypeError, 'This product is <b>not</b> redistributable.'
  204.         self.version=version=strip(version)
  205.         self.configurable_objects_=configurable_objects
  206.         self.redistributable=redistributable
  207.         RESPONSE.redirect('Distributions/%s-%s.tar.gz' % (self.id, version))
  208.         
  209.     def _distribution(self):
  210.         # Return a distribution
  211.         if self.__dict__.has_key('manage_options'):
  212.             raise TypeError, 'This product is <b>not</b> redistributable.'
  213.  
  214.         id=self.id
  215.         
  216.         import tar
  217.         rot=rotor.newrotor(id+' shshsh')
  218.         ar=tar.tgzarchive("%s-%s" % (id, self.version))
  219.         prefix="lib/python/Products/%s/" % self.id
  220.  
  221.         # __init__.py
  222.         ar.add(prefix+"__init__.py",
  223.                '''"Product %s"
  224.                ''' % id
  225.                )
  226.  
  227.         # Extensions
  228.         pp=id+'.'
  229.         lpp=len(pp)
  230.         ed=os.path.join(INSTANCE_HOME,'Extensions')
  231.         if os.path.exists(ed):
  232.             for name in os.listdir(ed):
  233.                 suffix=''
  234.                 if name[:lpp]==pp:
  235.                     path=os.path.join(ed, name)
  236.                     try:
  237.                         f=open(path)
  238.                         data=f.read()
  239.                         f.close()
  240.                         if name[-3:]=='.py':
  241.                             data=rot.encrypt(zlib.compress(data))
  242.                             suffix='p'
  243.                     except: data=None
  244.                     if data:
  245.                         ar.add("%sExtensions/%s%s" %
  246.                                (prefix,name[lpp:],suffix),
  247.                                data)
  248.  
  249.         # version.txt
  250.         ar.add(prefix+'version.txt', self.version)
  251.  
  252.         # product.dat
  253.         f=CompressedOutputFile(rot)
  254.         if self.redistributable:
  255.             # Since it's redistributable, make all objects configurable.
  256.             objectList = self._objects
  257.         else:
  258.             objectList = tuple(filter(
  259.                 lambda o, obs=self.configurable_objects_:
  260.                 o['id'] in obs,
  261.                 self._objects))
  262.         meta={
  263.             '_objects': objectList,
  264.             'redistributable': self.redistributable,
  265.             }
  266.         f.write(cPickle.dumps(meta,1))
  267.  
  268.         self._p_jar.exportFile(self._p_oid, f)
  269.         ar.add(prefix+'product.dat', f.getdata())
  270.  
  271.         ar.finish()
  272.         return str(ar)
  273.  
  274.     class Distributions(Acquisition.Explicit):
  275.         "Product Distributions"
  276.  
  277.         def __bobo_traverse__(self, REQUEST, name):
  278.             if name[-7:] != '.tar.gz': raise 'Invalid Name', name
  279.             l=find(name,'-')
  280.             id, version = name[:l], name[l+1:-7]
  281.             product=self.aq_parent
  282.             if product.id==id and product.version==version:
  283.                 return Distribution(product)
  284.  
  285.             raise 'Invalid version or product id', name
  286.  
  287.     Distributions=Distributions()
  288.  
  289.     manage_traceback=Globals.HTMLFile('traceback',globals())
  290.     manage_readme=Globals.HTMLFile('readme',globals())
  291.     def manage_get_product_readme__(self):
  292.         try:
  293.             return open(os.path.join(self.home, 'README.txt')).read()
  294.         except: return ''
  295.  
  296.     def permissionMappingPossibleValues(self):
  297.         return self.possible_permissions()
  298.  
  299.     def zclass_product_name(self):
  300.         return self.id
  301.  
  302.     def getProductHelp(self):
  303.         """
  304.         Returns the ProductHelp object associated
  305.         with the Product.
  306.         """
  307.         if not hasattr(self, 'Help'):
  308.             self._setObject('Help', ProductHelp('Help', self.id))
  309.         return self.Help
  310.  
  311. class CompressedOutputFile:
  312.     def __init__(self, rot):
  313.         self._c=zlib.compressobj()
  314.         self._r=[]
  315.         self._rot=rot
  316.         rot.encrypt('')
  317.  
  318.     def write(self, s):
  319.         self._r.append(self._rot.encryptmore(self._c.compress(s)))
  320.  
  321.     def getdata(self):
  322.         self._r.append(self._rot.encryptmore(self._c.flush()))
  323.         return join(self._r,'')
  324.  
  325. class CompressedInputFile:
  326.     _done=0
  327.     def __init__(self, f, rot):
  328.         self._c=zlib.decompressobj()
  329.         self._b=''
  330.         if type(rot) is type(''): rot=rotor.newrotor(rot)
  331.         self._rot=rot
  332.         rot.decrypt('')
  333.         self._f=f
  334.  
  335.     def _next(self):
  336.         if self._done: return
  337.         l=self._f.read(8196)
  338.         if not l:
  339.             l=self._c.flush()
  340.             self._done=1
  341.         else:
  342.             l=self._c.decompress(self._rot.decryptmore(l))
  343.         self._b=self._b+l
  344.  
  345.     def read(self, l=None):
  346.         if l is None:
  347.             while not self._done: self._next()
  348.             l=len(self._b)
  349.         else:
  350.             while l > len(self._b) and not self._done: self._next()
  351.         r=self._b[:l]
  352.         self._b=self._b[l:]
  353.  
  354.         return r
  355.  
  356.     def readline(self):
  357.         l=find(self._b, '\n')
  358.         while l < 0 and not self._done:
  359.             self._next()
  360.             l=find(self._b, '\n')
  361.         if l < 0: l=len(self._b)
  362.         else: l=l+1
  363.         r=self._b[:l]
  364.         self._b=self._b[l:]
  365.         return r
  366.  
  367. class Distribution:
  368.     "A distribution builder"
  369.     
  370.     def __init__(self, product):
  371.         self._product=product
  372.  
  373.     def index_html(self, RESPONSE):
  374.         "Return distribution data"
  375.         r=self._product._distribution()
  376.         RESPONSE['content-type']='application/x-gzip'
  377.         return r
  378.  
  379. def initializeProduct(productp, name, home, app):
  380.     # Initialize a levered product
  381.     products=app.Control_Panel.Products
  382.  
  383.     if hasattr(productp, '__import_error__'): ie=productp.__import_error__
  384.     else: ie=None
  385.  
  386.     try: fver=strip(open(home+'/version.txt').read())
  387.     except: fver=''
  388.     old=None
  389.     try:
  390.         if ihasattr(products,name):
  391.             old=getattr(products, name)
  392.             if ihasattr(old,'version') and old.version==fver:
  393.                 if hasattr(old, 'import_error_') and \
  394.                    old.import_error_==ie:
  395.                     # Version hasn't changed. Don't reinitialize.
  396.                     return old
  397.     except: pass
  398.     
  399.     disable_distribution = 1
  400.     try:
  401.         f=CompressedInputFile(open(home+'/product.dat','rb'), name+' shshsh')
  402.     except:
  403.         f=fver and (" (%s)" % fver)
  404.         product=Product(name, 'Installed product %s%s' % (name,f))
  405.     else:
  406.         meta=cPickle.Unpickler(f).load()
  407.         product=app._p_jar.importFile(f)
  408.         if meta.get('redistributable', 0):
  409.             disable_distribution = 0
  410.         product._objects=meta['_objects']
  411.  
  412.     if old is not None:
  413.         app._manage_remove_product_meta_type(product)
  414.         products._delObject(name)
  415.         for id, v in old.objectItems():
  416.             try: product._setObject(id, v)
  417.             except: pass
  418.  
  419.     products._setObject(name, product)
  420.     #product.__of__(products)._postCopy(products)
  421.     product.icon='p_/InstalledProduct_icon'
  422.     product.version=fver
  423.     product.home=home
  424.     if disable_distribution:
  425.         product.manage_options=Folder.manage_options
  426.         product._distribution=None
  427.         product.manage_distribution=None
  428.     product.thisIsAnInstalledProduct=1
  429.  
  430.     if ie:
  431.         product.import_error_=ie
  432.         product.title='Broken product %s' % name
  433.         product.icon='p_/BrokenProduct_icon'
  434.         product.manage_options=(
  435.             {'label':'Traceback', 'action':'manage_traceback'},
  436.             )
  437.  
  438.     if os.path.exists(os.path.join(home, 'README.txt')):
  439.         product.manage_options=product.manage_options+(
  440.             {'label':'README', 'action':'manage_readme'},
  441.             )
  442.  
  443.     if os.environ.get('ZEO_CLIENT',''): get_transaction().abort()
  444.  
  445.     return product
  446.  
  447. def ihasattr(o, name):
  448.     return hasattr(o, name) and o.__dict__.has_key(name)
  449.